﻿using System;
using System.Security.Principal;
using System.Web;
using System.Web.Script.Serialization;
using System.Web.Security;

/// <summary>
///Passport 的摘要说明
/// </summary>
public class Passport<TUser> : IPrincipal where TUser : class,new()
{
    private IIdentity _Identity;
    private TUser _User;
    /// <summary>
    /// 用户凭证
    /// </summary>
    /// <param name="ticket"></param>
    /// <param name="user"></param>
    public Passport(FormsAuthenticationTicket ticket, TUser user)
    {
        if (ticket == null)
        {
            throw new ArgumentNullException("FormsAuthenticationTicket ticket");
        }
        if (user == null)
        {
            throw new ArgumentNullException("TUser user");
        }
        _Identity = new FormsIdentity(ticket);
        _User = user;
    }
    public TUser User { get { return _User; } }
    public IIdentity Identity { get { return _Identity; } }

    /// <summary>
    /// 是否角色
    /// </summary>
    /// <param name="role"></param>
    /// <returns></returns>
    public bool IsInRole(string role)
    {
        IPrincipal principal = _User as IPrincipal;
        if (principal == null)
            throw new NotImplementedException();
        else
            return principal.IsInRole(role);
    }

    /// <summary>
    /// 用户登陆
    /// </summary>
    /// <param name="LoginName">用户名</param>
    /// <param name="User">用户属性</param>
    /// <param name="expiration">过期时间(分钟)</param>
    public static void SignIn(string loginName, TUser user, int expiration)
    {
        if (string.IsNullOrEmpty(loginName))
            throw new ArgumentNullException("loginName");
        if (user == null)
            throw new ArgumentNullException("userData");

        string userData = new JavaScriptSerializer().Serialize(user);
        FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, loginName, DateTime.Now, DateTime.Now.AddMonths(1), true, userData);
        string cookieValue = FormsAuthentication.Encrypt(ticket);

        HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, cookieValue);
        cookie.HttpOnly = true;
        cookie.Secure = FormsAuthentication.RequireSSL;
        cookie.Domain = FormsAuthentication.CookieDomain;
        cookie.Path = FormsAuthentication.FormsCookiePath;
        if (expiration > 0)
        {
            cookie.Expires = DateTime.Now.AddMinutes(expiration);
        }

        HttpContext context = HttpContext.Current;
        context.Response.Cookies.Remove(cookie.Name);
        context.Response.Cookies.Add(cookie);
    }

    /// <summary>
    /// 尝试从HttpRequest.Cookies中构造一个Passport对象
    /// </summary>
    /// <param name="request"></param>
    /// <returns></returns>
    public static Passport<TUser> TryParsePassport(HttpRequest request)
    {
        if (request == null)
            throw new ArgumentNullException("HttpRequest");

        HttpCookie cookie = request.Cookies[FormsAuthentication.FormsCookieName];
        if (cookie == null || string.IsNullOrEmpty(cookie.Value))
        {
            return null;
        }
        try
        {
            TUser userData = null;
            FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
            if (ticket != null && !string.IsNullOrEmpty(ticket.UserData))
            {
                userData = new JavaScriptSerializer().Deserialize<TUser>(ticket.UserData);
            }
            if (ticket != null && userData != null)
            {
                return new Passport<TUser>(ticket, userData);
            }
        }
        catch { }
        return null;
    }

    /// <summary>
    /// 根据HttpContext对象设置用户标识对象
    /// </summary>
    /// <param name="context"></param>
    public static void TrySetUserInfo(HttpContext context)
    {
        if (context == null)
            throw new ArgumentNullException("HttpContext");
        Passport<TUser> user = TryParsePassport(context.Request);
        if (user != null)
        {
            context.User = user;
        }
    }
}